#include "Building.h"
#include "../../Util/Physx.h"
#include "../../PhysicsLogic.h"
#include "../../Textures.h"
#include "../../Renderer.h"
#include "../../Game.h"
#include "../../ShapeData.h"

Model Building::model;
NxActorDesc Building::actorDesc;

LinkedList<Building*> Building::destroyed;

void Building::Load() { // static
	const float scale = 1.5f / 0.8f; //because the height of the house is 1.6m

	NxPhysicsSDK* physicsSDK = PhysicsLogic::GetPhysicsSDK();
	ModelBoundingVolume::SHAPETYPE modelShapeType = ModelBoundingVolume::CONVEX_SHAPE;

	model.SetLog(&Game::log);
	model.Load("res/models/house/house.obj", scale, physicsSDK, modelShapeType);

	Modelpart **modelparts = model.GetModelparts();
	for(int i = 0; i < model.GetNbModelparts(); ++i) {
		ModelBoundingVolume *bv = modelparts[i]->GetBoundingVolume();
		if(NxBoxShapeDesc *shDesc = bv->IsBoxShape()) {
			actorDesc.shapes.pushBack(shDesc);
		} else if(NxConvexShapeDesc *shDesc = bv->IsConvexShape())	{
			actorDesc.shapes.pushBack(shDesc);
		} else if(NxTriangleMeshShapeDesc *shDesc = bv->IsTriangleMeshShape()) {
			actorDesc.shapes.pushBack(shDesc);
		}
	}
}

void Building::DeleteDestroyed() { //static
	while(!destroyed.Empty()) {
		delete destroyed.GetFirst();
		destroyed.RemoveFirst();
	}
}

Building::Building(const NxVec3& pos) {
	this->hp = 12000.0f;

	const NxVec3 orientationVector(0, (rand()%360)/180.0f*NxPiF32, 0);
	NxMat33 rotationMatrix;
	rotationVectorToMatrix(orientationVector, &rotationMatrix);

	NxActorDesc ad = actorDesc;
	ad.globalPose.t = pos;
	ad.globalPose.M = rotationMatrix;

	actor = PhysicsLogic::GetScene()->createActor(ad);
	actor->setGroup(1);
	actor->setContactReportFlags(NX_NOTIFY_FORCES);
	actor->userData = this;

    //adding userdata to shape
    NxShape* const* shapes = actor->getShapes();
    NxU32 shapesCount = actor->getNbShapes();
    for(NxU32 i=0; i<shapesCount; ++i) {
        NxShape* shape = shapes[i];
        ShapeData *sd = new ShapeData();
        shape->userData = sd;
    }
}

Building::~Building() {
	NxShape* const* shapes = actor->getShapes();
	NxU32 shapesCount = actor->getNbShapes();
	for(NxU32 i=0; i<shapesCount; ++i) {
		NxShape* shape = shapes[i];
		if(shape->userData) {
			delete shape->userData;
		}
	}
	PhysicsLogic::GetScene()->releaseActor(*actor);
}

void Building::Draw() {
    bool buildingIsVisible = false;
    NxShape* const* shapes = actor->getShapes();
    NxU32 shapesCount = actor->getNbShapes();
    for(NxU32 i=0; i<shapesCount; ++i) {
        NxShape* shape = shapes[i];
        if(shape->userData) {
            ShapeData *sd = (ShapeData*)shape->userData;
            buildingIsVisible |= sd->isVisible;
            sd->isVisible = false;
        }
    }

    if(buildingIsVisible) {
        Renderer::ResetMaterial();

        float m[16];
        actor->getGlobalPose().getColumnMajor44(m);

        glPushMatrix();
        glMultMatrixf(m);
        model.Draw();
        glPopMatrix();
    }	
}

void Building::TakeDamage(float force) {
	hp -= force;

	if(hp <= 0) {
		for(int i=0; i<2; ++i) {
			Player* pickedPlayer = Game::GetPlayer(i);
			if(pickedPlayer->buildings.Contains(this)) {
				pickedPlayer->buildings.Remove(this);
				destroyed.Add(this);
				std::string message = StringBuilder() << "Haus von " << pickedPlayer->GetName() << " zerstört";
				PhysicsLogic::HudMessage(message);
			}
		}
	}
}
